import time
from qiniu import Auth, put_file, put_data
from threading import Lock
from typing import Dict, Any, BinaryIO


class QiniuHelper:
    """
    七牛云辅助类，用于生成上传凭证和管理上传凭证的缓存
    """
    # 上传凭证缓存
    _upload_token = None
    # 上传凭证过期时间（时间戳）
    _upload_token_expire_time = 0
    # 线程锁，防止并发生成token
    _lock = Lock()

    @classmethod
    def init(cls, access_key, secret_key, bucket_name):
        """初始化七牛云配置"""
        cls.access_key = access_key
        cls.secret_key = secret_key
        cls.bucket_name = bucket_name
        cls.auth = Auth(access_key, secret_key)

    @classmethod
    def get_upload_token(cls, force_refresh=False):
        """
        获取上传凭证，如果凭证不存在或已过期（默认有效期为1小时），则重新生成
        
        参数:
        - force_refresh: 是否强制刷新token
        
        返回:
        - upload_token: 上传凭证
        """
        current_time = int(time.time())
        
        # 如果token不存在、已过期或强制刷新
        if force_refresh or not cls._upload_token or current_time >= cls._upload_token_expire_time:
            with cls._lock:
                # 双重检查，防止多线程重复生成
                if force_refresh or not cls._upload_token or current_time >= cls._upload_token_expire_time:
                    # 生成上传凭证，默认有效期为3600秒（1小时）
                    token = cls.auth.upload_token(cls.bucket_name, expires=3600)
                    # 更新缓存
                    cls._upload_token = token
                    cls._upload_token_expire_time = current_time + 3600
        
        return cls._upload_token

    @classmethod
    def generate_download_url(cls, key, expires=3600):
        """
        生成私有空间的下载链接
        
        参数:
        - key: 文件名
        - expires: 链接有效期，单位为秒，默认1小时
        
        返回:
        - 下载链接
        """
        # 生成下载URL，需要七牛云存储域名
        if not hasattr(cls, 'domain'):
            raise ValueError("请先设置七牛云存储域名")
        
        # 生成私有下载链接
        base_url = f'http://{cls.domain}/{key}'
        private_url = cls.auth.private_download_url(base_url, expires=expires)
        return private_url

    @classmethod
    def set_domain(cls, domain):
        """设置七牛云存储域名"""
        cls.domain = domain
    
    @classmethod
    def upload_file(cls, file_obj: BinaryIO, key: str) -> Dict[str, Any]:
        """
        上传文件到七牛云
        
        参数:
        - file_obj: 文件对象
        - key: 文件名/路径
        
        返回:
        - 包含success状态和结果的字典
        """
        try:
            # 获取上传凭证
            token = cls.get_upload_token()
            
            # 上传文件
            ret, info = put_data(token, key, file_obj.read())
            
            if info.status_code == 200:
                # 上传成功，生成访问URL
                if hasattr(cls, 'domain'):
                    url = f'http://{cls.domain}/{key}'
                else:
                    url = f'http://{cls.bucket_name}.qiniudn.com/{key}'
                
                return {
                    'success': True,
                    'url': url,
                    'key': key,
                    'info': ret
                }
            else:
                return {
                    'success': False,
                    'error': f'上传失败: {info.text_body}',
                    'status_code': info.status_code
                }
                
        except Exception as e:
            return {
                'success': False,
                'error': f'上传异常: {str(e)}'
            }
    
    @classmethod
    def upload_file_by_path(cls, file_path: str, key: str) -> Dict[str, Any]:
        """
        根据文件路径上传文件到七牛云
        
        参数:
        - file_path: 本地文件路径
        - key: 文件名/路径
        
        返回:
        - 包含success状态和结果的字典
        """
        try:
            # 获取上传凭证
            token = cls.get_upload_token()
            
            # 上传文件
            ret, info = put_file(token, key, file_path)
            
            if info.status_code == 200:
                # 上传成功，生成访问URL
                if hasattr(cls, 'domain'):
                    url = f'http://{cls.domain}/{key}'
                else:
                    url = f'http://{cls.bucket_name}.qiniudn.com/{key}'
                
                return {
                    'success': True,
                    'url': url,
                    'key': key,
                    'info': ret
                }
            else:
                return {
                    'success': False,
                    'error': f'上传失败: {info.text_body}',
                    'status_code': info.status_code
                }
                
        except Exception as e:
            return {
                'success': False,
                'error': f'上传异常: {str(e)}'
            } 